MFC 用AfxBeginThread创建线程

您所在的位置:网站首页 win32 线程优先级 栈大小 MFC 用AfxBeginThread创建线程

MFC 用AfxBeginThread创建线程

2024-07-02 20:04| 来源: 网络整理| 查看: 265

代码以川建国同志的日常为例。川建国同志日常两件事,吹牛(brag)和咆哮(bark)。两件事随机发生,用创建线程的方式实现。

前两段内容部分摘自(https://blog.csdn.net/qq_33723441/article/details/54171230),有改正。

函数介绍

MFC提供了两个重载版的AfxBeginThread,一个用于用户界面线程,另一个用于工作者线程,区别在于用户界面线程能处理消息响应,而工作者线程不能。

本文只谈工作者线程的AfxBeginThread ,原型如下:

CWinThread* AFXAPI AfxBeginThread ( AFX_THREADPROC pfnThreadProc, //参数1 LPVOID pParam, //参数2 int nPriority, //参数3 UINT nStackSize, //参数4 DWORD dwCreateFlags, //参数5 LPSECURITY_ATTRIBUTES lpSecurityAttrs //参数6 )

其中: 参数1 线程的入口函数,必须是静态成员函数,声明一定要如下:

static UINT MyThreadFunction( LPVOID pParam );

参数2 传递入线程的参数,类型为LPVOID,所以我们可以传递一个结构体入线程。

参数3~5是默认参数,可以省略:

参数4指定线程的堆栈大小,如果为0,则与创建该线程的线程相同;

参数5是一个创建标识,如果是CREATE_SUSPENDED,则在悬挂状态创建线程,在线程创建后线程挂起,否则线程在创建后开始线程的执行。

参数6表示线程的安全属性,NT下有用。

 

实际中

实际中我们经常这样用:

AfxBeginThread(ThreadProc,this);

看到这儿我是挺懵的,参数2应该是给ThreadProc的参数么,怎么给传了个this指针?

后来明白了,通常这里的入口函数ThreadProc是这么个函数:

首先,它是当前类的静态成员函数;

其次,它的参数是当前类;

最后,他的作用是调用当前类的另一个成员函数。

 

建国同志案例

这么说很抽象,因此我想了个例子。

类名是TrumpDaily(川建国同志的日常),.h声明如下:

class CTrumpDaily { public: CString ms_sentence; //汇报川建国言行的CString字符串 void Decide(); void Brag(); void Bark(); static UINT doBrag(void* pParam); static UINT doBark(void* pParam); };

.cpp实现:

成员函数是:

TrumpDaily::Decide,川建国决定一下今天做什么,吹牛(brag)还是咆哮(bark)

void CTrumpDaily::Decide() { // 创建范围[0,1]的随机数i int i = rand() % 2 ; switch (i) { case 0: AfxBeginThread(doBrag, this); //i是0就创建个线程开始吹牛 break; case 1: AfxBeginThread(doBark, this); //i是1就创建个线程开始在那吠 break; } }

两个线程的入口函数是doBrag和doBark:

UINT CTrumpDaily::doBrag(void* pParam) { // 新建一个CTrumpDaily对象,调用其Brag()成员函数 CTrumpDaily* aDay = (CTrumpDaily*)pParam; aDay->Brag(); return 0; } UINT CTrumpDaily::doBark(void* pParam) { // 新建一个CTrumpDaily对象,调用其Bark()成员函数 CTrumpDaily* aDay = (CTrumpDaily*)pParam; aDay->Bark(); return 0; }

可以看到,这两个入口函数本身不干实事,它俩只是调用干实事的成员函数:

void CTrumpDaily::Brag() { ms_sentence = "Trump brags: Nobody lies better than I do."; } void CTrumpDaily::Bark() { ms_sentence = "Trump barks: CHINA! CHINA!"; }

最后MFC的单击消息按钮处理:

void CPlayMFCDBDlg::OnBnClickedAddButton() { // 按钮对应的变量是m_edit_sum,把川普的言行赋给它显示在对话框里 CTrumpDaily aDay; //新建一个CTrumpDaily对象 aDay.Decide(); //让它决定下做哪件事 m_edit_sum = aDay.ms_sentence; //把它的言论传给文本框变量 UpdateData(FALSE); //更新文本框 }

这样一个简单的MFC程序就搭好了,简洁又大方,干净又卫生:

但是这篇博客到此就该完了吗?并没有,以上代码是有bug的。反复戳"Trump Today"按钮,会发现文本框有时有川普的言论,但还有时是空的!多点击此后,程序还会崩溃!为什么?

 

正确的消息处理函数如下:

void CPlayMFCDBDlg::OnBnClickedAddButton() { // 按钮对应的变量是m_edit_sum,把川普的言行赋给它显示在对话框里 CTrumpDaily aDay; aDay.Decide(); Sleep(100); //这很重要 m_edit_sum = aDay.ms_sentence; //这是雷点 UpdateData(FALSE); }

Sleep(100)这句为啥重要呢?线程是单独运行的,有肯能主程序已经执行到m_edit_sum = aDay.ms_sentence了,线程刚好也在访问aDay.ms_sentence,这就打架了。至于什么时候打架就是看天意了。

所以加一句Sleep,让主程序等一等它的人民,一切就安好了。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3